﻿#region License

// Droid Manager - An Android Phone Tools Suite
// Copyright (C) 2011
// 
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

#endregion

using System;
using System.Drawing;
using System.Reflection;
using System.Threading;
using DroidManager.Log;
using DroidManager.Plugins.Interfaces;
using Managed.Adb;

namespace DroidManager.Plugins
{
    /// <summary>
    /// Loads Plugins
    /// </summary>
    internal class Plugin
    {
        /// <summary>
        /// Used to store plugin istance
        /// </summary>
        private IPlugin _instance;

        /// <summary>
        /// Logger
        /// </summary>
        private Logger _log = Logger.Instance;

        /// <summary>
        /// Determines if plugin has to be run ina new thread
        /// </summary>
        internal bool Threaded = false;

        /// <summary>
        /// Assembly Path
        /// </summary>
        internal string Path { get; private set; }

        /// <summary>
        /// Plugin's Thread
        /// </summary>
        internal Thread t { get; private set; }

        /// <summary>
        /// Constructor method
        /// </summary>
        /// <param name="filePath">Plugin file path</param>
        /// <param name="threaded"><c>true</c> if you want to run plugin in new thread</param>
        internal Plugin(string filePath, bool threaded)
        {
            Path = filePath;
            Threaded = threaded;
        }

        /// <summary>
        /// Loads plugin in memory
        /// </summary>
        internal bool Load()
        {
            try
            {
                Assembly Asm;
                Type[] T;
                AssemblyName asn = new AssemblyName();

                // NOTE Loads only Any CPU compiled plugins, LoadFile makes no discrimination
                Asm = Assembly.LoadFrom(Path);
                Byte i = 0;
                for (int a = 0; a < Asm.GetTypes().Length; a++)
                {
                    T = Asm.GetTypes();
                    if (object.ReferenceEquals(T[a].GetInterface("IPlugin"), typeof (IPlugin)))
                    {
                        _instance = (IPlugin) Asm.CreateInstance(T[a].FullName);
                        i += 1;
                    }
                }
                if (i > 1 | i == 0)
                {
                    _log.Error(string.Format("{0} plugin Classes in {1}", i.ToString(), Path));
                    _instance = null;
                    return false;
                }
                _log.Info(string.Format("Loaded Assembly {0}", Path));
                return true;
            }
            catch (Exception e)
            {
                _log.Error(string.Format("Error loading plugin {0} [{1}]", Path, e.ToString()));
                return false;
            }
        }

        #region Plugin Access

        internal void Start(Device device, string[] parameters)
        {
            if (Threaded)
            {
                t = new Thread(() => OnStart(device, parameters));
                t.Name = Name;
                t.SetApartmentState(ApartmentState.STA);
                t.Start();
            }
            else
            {
                OnStart(device, parameters);
            }
        }

        /// <summary>
        /// Calls plugin's OnStart method
        /// </summary>
        private void OnStart(Device device, string[] parameters)
        {
            _instance.OnStart(device, parameters);
        }

        /// <summary>
        /// Plugin's Name
        /// </summary>
        internal string Name
        {
            get
            {
                if (_instance.Name == null | _instance.Name == "")
                {
                    return this.Path;
                }
                else
                {
                    return _instance.Name;
                }
            }
        }

        /// <summary>
        /// Plugin's Icon
        /// </summary>
        internal Image Icon
        {
            get { return _instance.Icon; }
        }

        /// <summary>
        /// Check if plugin has to be showed in main window
        /// </summary>
        internal bool ShowInMenu
        {
            get { return _instance.ShowInMenu; }
        }

        #endregion //Plugin Access
    }
}